﻿using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;

namespace Ast.Core.Services.Extensions
{
    public static class MemoryStreamExtensions
    {
        public static T ReadAs<T>(this MemoryStream memoryStream, long? position = null)
        {
            if (position.HasValue)
            {
                memoryStream.Seek(position.Value, SeekOrigin.Begin);
            }

            var size = Marshal.SizeOf<T>();
            var streamBuffer = new byte[size];
            memoryStream.Read(streamBuffer, 0, size);

            var buffer = Marshal.AllocHGlobal(size);
            Marshal.Copy(streamBuffer, 0, buffer, size);
            var retVal = Marshal.PtrToStructure<T>(buffer);
            Marshal.FreeHGlobal(buffer);
            return retVal;
        }

        public static T[] ReadArrayAs<T>(this MemoryStream memoryStream, int length)
        {
            var retVal = new List<T>(length);
            for (var i = 0; i < length; i++)
            {
                var val = memoryStream.ReadAs<T>();
                retVal.Add(val);
            }
            return retVal.ToArray();
        }

        public static T[] ReadArrayAs<T>(this MemoryStream memoryStream)
        {
            var retVal = new List<T>();
            for (var i = 0;; i++)
            {
                var val = memoryStream.ReadAs<T>();
                if (val.Equals(default(T)))
                {
                    break;
                }
                retVal.Add(val);
            }
            return retVal.ToArray();
        }

        public static void WriteAs<T>(this MemoryStream memoryStream, T val, long? position = null)
        {
            if (position.HasValue)
            {
                memoryStream.Seek(position.Value, SeekOrigin.Begin);
            }

            var size = Marshal.SizeOf<T>();
            var streamBuffer = new byte[size];

            var buffer = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(val, buffer, true);
            Marshal.Copy(buffer, streamBuffer, 0, size);
            Marshal.FreeHGlobal(buffer);

            memoryStream.Write(streamBuffer, 0, size);
        }
    }
}